#!/usr/bin/env python3
"""
Web application for the Archive Audit System.
This provides a web interface to interact with the archive audit functionality.
"""

from flask import Flask, render_template, request, redirect, url_for, session, jsonify, flash
import os
import json
import pandas as pd
from archive_audit import ArchiveAuditSystem, PermissionManager, StructuredDataArchiver, UnstructuredDataArchiver
from werkzeug.utils import secure_filename
import tempfile
import shutil

app = Flask(__name__)
app.secret_key = os.urandom(24)  # For session management

# Initialize the system
system = ArchiveAuditSystem()

# Configure upload folder
UPLOAD_FOLDER = tempfile.mkdtemp()
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024  # 100MB max upload

@app.route('/')
def index():
    """Render the main page or redirect to login if not authenticated."""
    if 'username' not in session:
        return redirect(url_for('login'))
    return render_template('index.html', username=session['username'], role=session.get('role', ''))

@app.route('/login', methods=['GET', 'POST'])
def login():
    """Handle user login."""
    error = None
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        
        if system.login(username, password):
            session['username'] = username
            # Get user role
            with open(system.permission_manager.permission_file, 'r') as f:
                permissions = json.load(f)
                session['role'] = permissions['users'][username]['role']
            
            flash(f'Welcome, {username}!', 'success')
            return redirect(url_for('index'))
        else:
            error = 'Invalid credentials. Please try again.'
    
    return render_template('login.html', error=error)

@app.route('/logout')
def logout():
    """Handle user logout."""
    system.logout()
    session.pop('username', None)
    session.pop('role', None)
    flash('You have been logged out.', 'info')
    return redirect(url_for('login'))

@app.route('/users', methods=['GET', 'POST'])
def users():
    """Manage users (admin only)."""
    if 'username' not in session:
        return redirect(url_for('login'))
    
    if session.get('role') != 'admin':
        flash('Access denied. Admin privileges required.', 'danger')
        return redirect(url_for('index'))
    
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        role = request.form['role']
        
        if system.add_user(username, password, role):
            flash(f'User {username} added successfully.', 'success')
        else:
            flash(f'Failed to add user {username}.', 'danger')
    
    # Get all users
    with open(system.permission_manager.permission_file, 'r') as f:
        permissions = json.load(f)
        users = [{'username': username, 'role': user_data['role']} 
                for username, user_data in permissions['users'].items()]
    
    return render_template('users.html', users=users)

@app.route('/archive-db', methods=['GET', 'POST'])
def archive_db():
    """Archive a structured database."""
    if 'username' not in session:
        return redirect(url_for('login'))
    
    if request.method == 'POST':
        description = request.form['description']
        
        # Check if the post request has the file part
        if 'db_file' not in request.files:
            flash('No file part', 'danger')
            return redirect(request.url)
        
        file = request.files['db_file']
        
        # If user does not select file, browser also
        # submit an empty part without filename
        if file.filename == '':
            flash('No selected file', 'danger')
            return redirect(request.url)
        
        if file:
            filename = secure_filename(file.filename)
            filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
            file.save(filepath)
            
            try:
                archive_path = system.archive_structured_data(filepath, description)
                flash(f'Database archived successfully to {archive_path}', 'success')
            except Exception as e:
                flash(f'Error: {str(e)}', 'danger')
            
            # Clean up the temporary file
            os.remove(filepath)
    
    return render_template('archive_db.html')

@app.route('/archive-files', methods=['GET', 'POST'])
def archive_files():
    """Archive unstructured files."""
    if 'username' not in session:
        return redirect(url_for('login'))
    
    if request.method == 'POST':
        description = request.form['description']
        
        # Check if the post request has the file part
        if 'files[]' not in request.files:
            flash('No file part', 'danger')
            return redirect(request.url)
        
        files = request.files.getlist('files[]')
        
        # If user does not select file, browser also
        # submit an empty part without filename
        if not files or files[0].filename == '':
            flash('No selected files', 'danger')
            return redirect(request.url)
        
        # Create a temporary directory for the files
        temp_dir = os.path.join(app.config['UPLOAD_FOLDER'], 'temp_upload')
        os.makedirs(temp_dir, exist_ok=True)
        
        # Save all files to the temporary directory
        for file in files:
            filename = secure_filename(file.filename)
            filepath = os.path.join(temp_dir, filename)
            
            # Create subdirectories if needed
            os.makedirs(os.path.dirname(filepath), exist_ok=True)
            file.save(filepath)
        
        try:
            archive_path = system.archive_unstructured_data(temp_dir, description)
            flash(f'Files archived successfully to {archive_path}', 'success')
        except Exception as e:
            flash(f'Error: {str(e)}', 'danger')
        
        # Clean up the temporary directory
        shutil.rmtree(temp_dir)
    
    return render_template('archive_files.html')

@app.route('/list-db-archives')
def list_db_archives():
    """List all structured database archives."""
    if 'username' not in session:
        return redirect(url_for('login'))
    
    archives = system.structured_archiver.list_archives()
    return render_template('list_db_archives.html', archives=archives)

@app.route('/list-file-archives')
def list_file_archives():
    """List all unstructured file archives."""
    if 'username' not in session:
        return redirect(url_for('login'))
    
    archives = system.unstructured_archiver.list_archives()
    return render_template('list_file_archives.html', archives=archives)

@app.route('/audit-db/<int:archive_id>', methods=['GET', 'POST'])
def audit_db(archive_id):
    """Audit a structured database archive."""
    if 'username' not in session:
        return redirect(url_for('login'))
    
    error = None
    results = None
    
    # Get archive info
    conn = system.structured_archiver._init_index_db()
    conn = sqlite3.connect(system.structured_archiver.index_db)
    conn.row_factory = sqlite3.Row
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM archives WHERE id = ?", (archive_id,))
    archive = dict(cursor.fetchone())
    conn.close()
    
    if request.method == 'POST':
        sql_query = request.form['sql_query']
        
        try:
            df = system.audit_structured_data(archive_id, sql_query)
            results = df.to_dict('records')
            columns = df.columns.tolist()
        except Exception as e:
            error = str(e)
    
    return render_template('audit_db.html', archive=archive, results=results, 
                          columns=columns if results else [], error=error)

@app.route('/audit-files/<int:archive_id>')
def audit_files(archive_id):
    """Audit an unstructured file archive."""
    if 'username' not in session:
        return redirect(url_for('login'))
    
    try:
        # Get archive info
        conn = sqlite3.connect(system.unstructured_archiver.index_db)
        conn.row_factory = sqlite3.Row
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM archives WHERE id = ?", (archive_id,))
        archive = dict(cursor.fetchone())
        conn.close()
        
        # Get files in archive
        files = system.unstructured_archiver.get_archive_files(archive_id)
        
        return render_template('audit_files.html', archive=archive, files=files)
    except Exception as e:
        flash(f'Error: {str(e)}', 'danger')
        return redirect(url_for('list_file_archives'))

@app.route('/search', methods=['GET', 'POST'])
def search():
    """Search archives."""
    if 'username' not in session:
        return redirect(url_for('login'))
    
    db_results = []
    file_results = []
    file_content_results = []
    
    if request.method == 'POST':
        query = request.form['query']
        search_type = request.form['search_type']
        
        if search_type == 'db' or search_type == 'all':
            db_results = system.structured_archiver.search_archives(query)
        
        if search_type == 'file' or search_type == 'all':
            file_results = system.unstructured_archiver.search_archives(query)
        
        if search_type == 'content' or search_type == 'all':
            file_content_results = system.unstructured_archiver.search_files(query)
    
    return render_template('search.html', db_results=db_results, 
                          file_results=file_results, 
                          file_content_results=file_content_results)

@app.route('/api/db-archives')
def api_db_archives():
    """API endpoint to get structured database archives."""
    if 'username' not in session:
        return jsonify({'error': 'Not authenticated'}), 401
    
    archives = system.structured_archiver.list_archives()
    return jsonify(archives)

@app.route('/api/file-archives')
def api_file_archives():
    """API endpoint to get unstructured file archives."""
    if 'username' not in session:
        return jsonify({'error': 'Not authenticated'}), 401
    
    archives = system.unstructured_archiver.list_archives()
    return jsonify(archives)

@app.route('/api/audit-db/<int:archive_id>', methods=['POST'])
def api_audit_db(archive_id):
    """API endpoint to audit a structured database archive."""
    if 'username' not in session:
        return jsonify({'error': 'Not authenticated'}), 401
    
    data = request.get_json()
    sql_query = data.get('sql_query')
    
    if not sql_query:
        return jsonify({'error': 'SQL query is required'}), 400
    
    try:
        df = system.audit_structured_data(archive_id, sql_query)
        return jsonify({
            'results': df.to_dict('records'),
            'columns': df.columns.tolist()
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 400

@app.route('/api/audit-files/<int:archive_id>')
def api_audit_files(archive_id):
    """API endpoint to audit an unstructured file archive."""
    if 'username' not in session:
        return jsonify({'error': 'Not authenticated'}), 401
    
    try:
        files = system.unstructured_archiver.get_archive_files(archive_id)
        return jsonify(files)
    except Exception as e:
        return jsonify({'error': str(e)}), 400

@app.route('/api/search', methods=['POST'])
def api_search():
    """API endpoint to search archives."""
    if 'username' not in session:
        return jsonify({'error': 'Not authenticated'}), 401
    
    data = request.get_json()
    query = data.get('query')
    search_type = data.get('search_type', 'all')
    
    if not query:
        return jsonify({'error': 'Search query is required'}), 400
    
    results = {
        'db_results': [],
        'file_results': [],
        'file_content_results': []
    }
    
    if search_type == 'db' or search_type == 'all':
        results['db_results'] = system.structured_archiver.search_archives(query)
    
    if search_type == 'file' or search_type == 'all':
        results['file_results'] = system.unstructured_archiver.search_archives(query)
    
    if search_type == 'content' or search_type == 'all':
        results['file_content_results'] = system.unstructured_archiver.search_files(query)
    
    return jsonify(results)

if __name__ == '__main__':
    import sqlite3
    app.run(debug=True)
